package com.stanwind.sync;

import com.alibaba.otter.canal.protocol.CanalEntry.RowData;
import com.stanwind.sync.listener.AbstractCanalListener;
import java.util.HashMap;
import java.util.Map;

/**
 * SyncContext 上下文
 *
 * @author : Stan
 * @version : 1.0
 * @date :  2020-05-25 11:43
 **/
public class SyncContext {
    /*
     * 保持当前线程独有信息的对象
     */
    private final static ThreadLocal<Map<Object, Object>> threadLocal = new ThreadLocal<>();

    /**
     * ROW DATA
     */
    private final static String CURRENT_ROW_DATA = "CURRENT_ROW_DATA";

    /**
     * DATA BEFORE
     */
    private final static String CURRENT_DATA_BEFORE = "CURRENT_DATA_BEFORE";

    /**
     * DATA AFTER
     */
    private final static String CURRENT_DATA_AFTER = "CURRENT_DATA_AFTER";

    /**
     * 默取得数据前后
     */
    private final static String CURRENT_IS_DATA_BEFORE = "CURRENT_IS_DATA_BEFORE";

    /**
     * 默取得数据前后
     */
    private final static String CURRENT_LISTENER = "CURRENT_LISTENER";

    /*
     * 向当前线程中存放信息
     * @param key
     * @param value
     */
    public static void setValue(Object key, Object value) {
        Map<Object, Object> threadLocalValueMap = threadLocal.get();
        if (threadLocalValueMap == null) {
            threadLocalValueMap = new HashMap<>();
            threadLocal.set(threadLocalValueMap);
        }
        threadLocalValueMap.put(key, value);
    }

    /*
     * 从当前线程中取得信息
     * @param key
     * @return
     */
    public static Object getValue(Object key) {
        Map<Object, Object> threadLocalValueMap = threadLocal.get();
        if (threadLocalValueMap == null) {
            return null;
        } else {
            return threadLocalValueMap.get(key);
        }
    }

    /*
     * 从当前线程中取得信息
     * @param key
     * @return
     */
    public static <T> T getValue(Object key, Class<T> clazz) {
        return clazz.cast(getValue(key));
    }

    /**
     * 清除当前threadlocal
     */
    public static void clear() {
        Map<Object, Object> threadLocalValueMap = threadLocal.get();
        if (threadLocalValueMap == null) {
            threadLocalValueMap = new HashMap<>();
            threadLocal.set(threadLocalValueMap);
        }

        threadLocalValueMap.clear();
    }

    public static void setCurrentRowData(Object object) {
        setValue(CURRENT_ROW_DATA, object);
    }

    public static void setCurrentDataBefore(Object object) {
        setValue(CURRENT_DATA_BEFORE, object);
    }

    public static void setCurrentDataAfter(Object object) {
        setValue(CURRENT_DATA_AFTER, object);
    }

    public static void setCurrentIsDataBefore(boolean object) {
        setValue(CURRENT_IS_DATA_BEFORE, object);
    }

    public static RowData getCurrentRowData() {
        return getValue(CURRENT_ROW_DATA, RowData.class);
    }

    public static Map<String, Object> getCurrentDataBefore() {
        return getValue(CURRENT_DATA_BEFORE, Map.class);
    }

    public static Map<String, Object> getCurrentDataAfter() {
        return getValue(CURRENT_DATA_AFTER, Map.class);
    }

    public static boolean getCurrentIsDataBefore() {
        return getValue(CURRENT_IS_DATA_BEFORE, Boolean.class);
    }

    public static <T> T getBeforeParam(String key, Class<T> clazz) {
        if (getCurrentDataBefore() == null) {
            return null;
        }

        return clazz.cast(getCurrentDataBefore().get(key));
    }

    public static <T> T getAfterParam(String key, Class<T> clazz) {
        if (getCurrentDataAfter() == null) {
            return null;
        }

        return clazz.cast(getCurrentDataAfter().get(key));
    }

    /**
     * 获取默认参数
     * 默认DELETE 从变更前取  INSERT、UPDATE 从变更后取
     * @param key
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T getParam(String key, Class<T> clazz) {
        Map<String, Object> map = getCurrentIsDataBefore() ? getCurrentDataBefore() : getCurrentDataAfter();
        if (map == null) {
            return null;
        }

        return clazz.cast(map.get(key));
    }

    /**
     * 获取当前listener
     * @param <T>
     * @return
     */
    public static <T extends AbstractCanalListener> T getCurrentListener() {
        return (T) getValue(CURRENT_LISTENER);
    }

    public static void setCurrentListener(AbstractCanalListener listener) {
        setValue(CURRENT_LISTENER, listener);
    }
}
